package com.tsystems.services;

import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityTransaction;

import com.tsystems.dao.PassengerDAO;
import com.tsystems.dao.TicketDAO;
import com.tsystems.dao.TimeTableElementDAO;
import com.tsystems.dao.TrainsEntityManager;
import com.tsystems.entities.Passenger;
import com.tsystems.entities.Station;
import com.tsystems.entities.Ticket;
import com.tsystems.entities.TimeTableElement;
import com.tsystems.entities.Train;

/**
 * 
 * @author 4194
 * 
 *         Класс, отвечающий за все операции с билетами.
 */
public class TicketServices {

	private static TicketServices instance;

	public static synchronized TicketServices getInstance() {
		if (instance == null) {
			instance = new TicketServices();
		}
		return instance;
	}

	private TicketServices() {
	}

	/**
	 * Метод, получающий список билетов текущего пользователя
	 * 
	 * @param login
	 *            - логин текущего пользователя
	 * @return Список билетов текущего пользователя если такой пользователь
	 *         есть, иначе пустой список.
	 */
	public synchronized List<Ticket> viewTickets(String login) {
		PassengerDAO passengerDAO = new PassengerDAO();
		Passenger passenger = passengerDAO.getPassenger(login);

		if (passenger == null) {
			return Collections.emptyList();
		}

		TicketDAO ticketDAO = new TicketDAO();
		List<Ticket> result = ticketDAO.getTicketsByPassenger(passenger);
		return result;
	}

	/**
	 * Метод осуществляющий операцию покупки билета текущим пользователем, в
	 * зависимости от многих параметров
	 * 
	 * @param fromStation
	 *            - станция отправления
	 * @param toStation
	 *            - станция прибытия
	 * @param fromTime
	 *            - время отправления
	 * @param train
	 *            - поезд
	 * @param arrivalTime
	 *            - время прибытия
	 * @param login
	 *            - логин текущего пользователя.
	 * @return "Билет успешно приобретен", если билеты (или группа билетов)
	 *         успешно добавлены в базу, иначе сообщение об ошибке
	 */
	public synchronized String buyTicket(Station fromStation,
			Station toStation, Date fromTime, Train train, Date arrivalTime,
			String login) {

		Date currentTime = Calendar.getInstance().getTime();
		if ((login == null)
				|| fromTime.getTime() - currentTime.getTime() < 600000) {
			return "Невозможно приобрести билет, до времени отправления осталось менее 10 минут.";
		}

		TicketDAO ticketDAO = new TicketDAO();
		PassengerDAO passengerDAO = new PassengerDAO();

		Passenger passengerFound = passengerDAO.getPassenger(login);

		if (passengerFound == null) {
			return "Невозможно купить билет. Пользователь отсутствует в базе. Обратитесь к администратору.";
		}
		TimeTableElementDAO tteDAO = new TimeTableElementDAO();
		TimeTableElement departureTTE = tteDAO
				.getTimeTableElementByDepartureInformation(train, fromStation,
						fromTime);

		List<TimeTableElement> arrivalList = tteDAO
				.getTimeTableElementByArrivalInformation(train, toStation,
						arrivalTime);
		List<TimeTableElement> path = null;
		for (TimeTableElement element : arrivalList) {
			path = TimeTableElementServices.getInstance().mergePath(
					departureTTE, element);
			if (!path.isEmpty()) {
				break;
			}

		}
		if (path == null || path.isEmpty()) {
			return "Не существует поездов, проходящих от " + fromStation
					+ " до " + toStation + " в это время";
		}
		EntityTransaction trx = TrainsEntityManager.getInstance()
				.getTransaction();
		try {
			trx.begin();
			for (TimeTableElement element : path) {
				if (ticketDAO.getTicketsByPassengerAndTTE(passengerFound,
						element) != null) {
					return "На данного пользователя билет уже зарегистрирован!";
				}
				if (ticketDAO.getTickestByTTE(element).size() >= train
						.getSeats()) {
					return "На данный поезд закончились билеты!";
				}

				ticketDAO.insertNotSafe(new Ticket(passengerFound, element));
			}
			trx.commit();
		} finally {
			if (trx.isActive()) {
				trx.rollback();
			}
		}

		return "Билет успешно приобретен";
	}

}
